#!/usr/bin/env python
# coding=utf-8
# Created on 2014-1-17
#
from model.model import *
from model.mail import send_mail
from tornado import ioloop, web, httpserver
from apscheduler.scheduler import Scheduler
from config.config import __VERSION__, PORT, initLog, CBGW_ADDR, BRAND, SMSNAME, SMSPWD, CALL_RATE, SMS_RATE, UNIT, CRENT
import simplejson as json, urllib2, urllib, math
from model import redis_model,num_redis_model
import threading
import thread
# 当前日期
def get_dt():
    return time.strftime('%Y-%m-%d', time.localtime(time.time()))

# 当前时间段
def get_tt():
    return time.strftime('%H', time.localtime(time.time()))

# 版本信息
class versionHandler(web.RequestHandler):
    def get(self):
        self.finish(__VERSION__)

#===============================SMS TASK=======================================

# 短信账户余额检查
def sms_balance(user, pwd):
    parms = {
             "act":'balance',
             "username":user,
             "passwd":pwd             
             }
    parms_string = urllib.urlencode(parms)
    url = "%s/sms_http.php?%s" % (SMS_URL, parms_string)
    result = urllib2.urlopen(url, timeout=3).read()
    balance = int(result) * 0.10
    logger.info(u"短信账户:%s 余额:%s" % (user, balance))
    print balance
    return balance
    result.close()

# 发送短信
def sms_send(phone, content):
    parms = {
             "act":'send',
             "username":SMSNAME,
             "passwd":SMSPWD,
             "phone":phone,
             "content":content             
             }
    parms_string = urllib.urlencode(parms)
    url = "%s/sms_mass.php?%s" % (SMS_URL, parms_string)
    logger.info(u"sms_url:%s" % url)
    try:
        urllib2.urlopen(url, timeout=3).read()
    except Exception, e:
        logger.error(u"更新发短信号码状态失败:%s, ERROR: %s" % (phone, e))

# 短信计费
def sms_deduction(task_id):
    if not task_id:return
    smsinfo = sms_info(task_id)  # 获取短信数量,费率,用户ID
    for sms in smsinfo:
        sms_rate = float((sms.get('sms_rate')) or SMS_RATE)  
        user = sms.get('user_id', '')  # 获取用户ID
        total = sms.get('total', 0)
    if not user:
        return
    else:
        sms_deduct(total, user)  # 发短信费用,减用户钱包
    write_sms_fee(sms_rate, task_id)  # 扣费记录    
        
            
# 扫描短信号码
def scan_sms():
    balance = sms_balance(SMSNAME, SMSPWD)  # 检查短信账户余额
    if balance <= 90:
        logger.info(u"短信账户余额不多:%s" % balance)
        send_mail(to_email)
    elif balance <= 10:
        logger.info(u"短信停止发送:%s" % balance)
        return
    else:
        result = send_sms()  # 取出需要发送短信的号码
        if not result: 
            print u"没有需要发短信的号码"
            return
        smslist = []
        for t in result:
            task_number = t.get('task_number', '')
            task_id = t.get('task_id', '')
            res = task_number.split(",")
            for n in res:
                smslist.append("%s" % n)
        number = ",".join(smslist)
        smscontent = sms_content(task_id)  # 短信内容
        logger.info(u"短信内容:%s" % smscontent)
        if not smscontent:
            logger.info(u"task_id:%s短信内容为空" % task_id)
            return
        for i in smscontent:
            msg = unicode(i['sms_content']).encode('gbk')  # 转GBK编码
        for sendsms in result:
            smslist.append(sendsms)
        sms_send(number, msg)  # 发送
        up_sms_status(task_number, task_id)  # 更新发送状态
        sms_deduction(task_id)  # 计费

#===============================CALL TASK=======================================

# 扫描群呼任务
def scan_task(): 
    num_redis_model.in_send_num_cbgw('eee')
    DT = get_dt()
    TT = get_tt() 
    result = query_task(DT, DT, TT, TT)  # 任务数据
    print result
    for t in result:
        redirect = t.get('redirect', 0)  # 转客服:0不转,1人工,2自动
        display_num = t.get('display_num', '')  # 透传号码
        display = 0 
        if len(display_num) > 8:display = 1  # 0不透传,1透传,根据透传号码长度设置透传状态
        voice_name = t.get('voice_name', '')  # 语音文件名
        concurrent = int(t.get('concurrent') or CRENT)  # 并发量
        task_id = t.get('id', '')  # 任务ID
        ser_number = t.get('ser_number', '')  # 客服号码
        ser_number = ser_number.split(',')
        user_id = t.get('user_id', '')  # 用户ID
        model = int(t.get('model') or UNIT)  # 计费模式,6+6,60+60
        rate = float(t.get('rate', 0))  # 费率
        end_date = str(t.get('end_date', ''))  # 任务结束日期
        ret = simultaneous(task_id)  # 并发量控制
        for q in ret:
            qty = int(q.get('total', 0))
        extend = {"user_id":user_id, "model":model, "rate":float(rate), "task_id":task_id}  # 扩展字段数据
        lmt = concurrent - qty
        
        logger.info("lmt:%s" % lmt)
        print task_id
        
        # cbgw的每秒接收的值
        if lmt >= SEND_CBGW_PER:
            lmt = SEND_CBGW_PER
        
        # 全局每秒发送数控制
#         if current_runing_num >= SEND_CBGW_PER:
#             current_runing_num += lmt
#             lmt = current_runing_num - SEND_CBGW_PER
#             break
            
        # 检查用户本地账户余额,余额不足直接返回
        # current_user_balance_arr = get_user_balance(user_id) 
        # user_balance = current_user_balance_arr[0]['balance']
        # if float(user_balance) <= USER_BALANCE + (0.5 * lmt):  #当前用户余额小于等于余额警告+并发量*1元
        #    logger.info(u"账户余额不多:%f" % user_balance)
        #    print u"账户余额不多:%f" % user_balance
        #    continue    
        task_number = query_number(task_id, lmt)
        print task_number
        index = 0
        for t in task_number:
            number = t.get('task_number', '')  # 群呼号码
            numid = t.get('id', '')  # 群呼号码id
            extend['numid'] = numid
            print 'number:', number
            snum = ser_number[index % len(ser_number)]  # 获取客服号码下标
            snum = snum.strip()
            send_num(number, number, voice_name, snum, display, display_num, redirect, FROM_URL, extend)  # 执行呼叫 
#             up_status_call(task_id, number)  # 更新为通话状态
            send_num_cbgw_param = {'task_id':task_id, 'user_id':user_id, 'number':number , 'voice_name' : voice_name , 'snum' : snum , 'display' : display , 'display_num' : display_num , 'redirect' : redirect , 'from_url' :FROM_URL, 'extend':extend}
#             logger.info("send_num_cbgw_param:%s" % send_num_cbgw_param)
#             num_redis_model.in_send_num_cbgw(send_num_cbgw_param)
            index += 1
        break  # 只执行一条任务

# 发送号码
def send_num(user_id, task_number, voicename, ser_num='', display='0', display_num='', redirect='0', fromurl='', extend=''):
    parms = {
             "brandid":BRAND,
             "uid":user_id,
             "caller":task_number,
             "callee":ser_num,
             "display":display,
             "displaynum":display_num,
             "redirect":redirect,
             "fromurl":fromurl,
             "voicename":voicename,
             "cbtype":2,
             "extend":json.dumps(extend, separators=(",", ":")),
             }
    parms_string = urllib.urlencode(parms)
    url = "%s/autocall?%s" % (CBGW_ADDR, parms_string)
    try:
        logger.info(u"call_url：%s" % url)
        urllib2.urlopen(url, timeout=3).read()
    except Exception, e:
        logger.error(u"url open error, url: %s, ERROR: %s" % (url, e))

# 更新任务
def update_task():
    DT = get_dt()
    result = check_task(DT, DT)  # 检查任务
    print result
    for i in result:
        task_id = i.get('id', '')
        end_date = str(i.get('end_date', ''))
        if end_date > DT:
            res = query_number(task_id, 1)
            if not res:
                up_status_finish(task_id)
            else:return
        else:
            res = query_number(task_id, 1)
            if not res:
                up_status_finish(task_id)
            else:return            


# 组合语句update号码状态和通话费用记录
def join_numstatus_sql(fee, acalltime, bcalltime, redirectret, caller, task_id):
    pass


# 发送到CBGW
def send_num_to_cbgw():
    while 1:
        try:
            comebakcalls = redis_model.out_comebakcallnotify(50)
            if not comebakcalls:
                time.sleep(3)
                continue
#                 break
#                 return
            for comebakcall in comebakcalls:
                comebakcall_dict = eval(comebakcall)
                acalltime = comebakcall_dict['Acalltime']
                bcalltime = comebakcall_dict['Bcalltime']
                redirectret = comebakcall_dict['redirectret']
                caller = comebakcall_dict['caller']
                task_id = comebakcall_dict['task_id']
                fee = comebakcall_dict['fee']
                user_id = comebakcall_dict['user_id']
                numid = comebakcall_dict['numid']
                write_num_data(fee, acalltime, bcalltime, redirectret, caller, task_id, user_id, numid)  # 写入呼叫数据
                redis_model.rm_comebakcallnotify(comebakcall)
        except:
            redis_model.in_comebakcallnotify(comebakcall)
            logger.error('have a error', exc_info=True)
            
            
# (计费,更新号码状态,任务状态)
def comebakcallnotify():
    comebakcall = None    
    while True:
        try:
            comebakcalls = redis_model.out_comebakcallnotify(50) 
            if not comebakcalls:
                time.sleep(3)
                continue
#                 break
#                 return
            for comebakcall_v in comebakcalls:
                comebakcall = comebakcall_v
                comebakcall_dict = eval(comebakcall)
                acalltime = comebakcall_dict['Acalltime']
                bcalltime = comebakcall_dict['Bcalltime']
                redirectret = comebakcall_dict['redirectret']
                caller = comebakcall_dict['caller']
                task_id = comebakcall_dict['task_id']
                fee = comebakcall_dict['fee']
                user_id = comebakcall_dict['user_id']
                numid = comebakcall_dict['numid']
                write_num_data(fee, acalltime, bcalltime, redirectret, caller, task_id, user_id, numid)  # 写入呼叫数据
                redis_model.rm_comebakcallnotify(comebakcall)
        except:
            if comebakcall != None:
                redis_model.in_comebakcallnotify(comebakcall)
                logger.error('have a error', exc_info=True)
#     try:
#         comebakcalls = redis_model.out_comebakcallnotify(50)
#         if not comebakcalls:
#             return
#         for comebakcall in comebakcalls:
#             comebakcall_dict = eval(comebakcall)
# #             comebacknotify_param = {"Acalltime":acalltime , 'Bcalltime' : bcalltime , "redirectret" : redirectret , "caller" : caller , 'task_id' : task_id , "fee" : fee , "user_id" :user_id}
#             acalltime = comebakcall_dict['Acalltime']
#             bcalltime = comebakcall_dict['Bcalltime']
#             redirectret = comebakcall_dict['redirectret']
#             caller = comebakcall_dict['caller']
#             task_id = comebakcall_dict['task_id']
#             fee = comebakcall_dict['fee']
#             user_id = comebakcall_dict['user_id']
#             write_num_data(fee,acalltime, bcalltime, redirectret, caller, task_id,user_id)  # 写入呼叫数据
# #             call_deduct(fee, user_id)  # 群呼扣费
# #             write_call_fee(fee, caller, task_id)  # 记录费用
#             redis_model.rm_comebakcallnotify(comebakcall)
#     except:
#         redis_model.in_comebakcallnotify(comebakcall)
#         logger.error('have a error', exc_info=True)
               
# 应答接口,
class comebackHandler(web.RequestHandler):
    '''计费模式 6==math.ceil(通话时长/6.0)*(费率/10); 60==math.ceil(通话时长/6.0)*费率    '''
    def get(self):
        try:
            number = self.get_argument('caller', '')  # 主叫号码
            if not number:
                logger.info(u"杀杀杀")
                return
            else:
                caller = number[-11:] 
            redirectret = int(self.get_argument('redirectret', ''))  # 是否转客服
            extend = self.get_argument('extend', '')  # 扩展信息,用户id,计费模式,费率
            acalltime = int(self.get_argument('Acalltime', 0))  # A路通话时长
            bcalltime = int(self.get_argument('Bcalltime', 0))  # B路通话时长
            ex = json.loads(extend)
            user_id = int(ex.get('user_id', ''))  # 用户ID
            model = int(ex.get('model', UNIT))  # 计费模式,默认6秒计费单元
            rate = float(ex.get('rate', CALL_RATE))  # 默认费率,5分
            task_id = int(ex.get('task_id', ''))  # 群呼任务ID
            numid = int(ex.get('numid', ''))  # 群呼任务ID
            if model == 6:
                fee = math.ceil((acalltime + bcalltime) / 6.0) * (rate / 10)  # 6秒计费
            elif model == 60:
                fee = math.ceil((acalltime + bcalltime) / 6.0) * rate  # 60秒计费
            else:
                logger.info(u"计费模式错误:%s" % model)
            comebacknotify_param = {'numid':numid, "Acalltime":acalltime , 'Bcalltime' : bcalltime , "redirectret" : redirectret , "caller" : caller , 'task_id' : task_id , "fee" : fee , "user_id" :user_id}
                                  
            redis_model.in_comebakcallnotify(comebacknotify_param)
            res = ({"result":0})  
        except:
            logger.error('have a error', exc_info=True)
            res = ({"result":5})  # 未知错误
        self.finish(res)
            
        
class Application(web.Application):
    def __init__(self):
        handlers = [
            (r"/comeback", comebackHandler),
            (r"/version", versionHandler)            
        ]
        settings = {
            "debug": True,
        }
        web.Application.__init__(self, handlers, **settings)   

# 接口服务(http)
def http_server():
    server = httpserver.HTTPServer(Application())
    server.listen(PORT)
    ioloop.IOLoop.instance().start()
    
#===============================REPORT=======================================
# 群呼任务报表   
def report_task():
    DT = get_dt()
    result = finish_task(DT)
    if not result:return
    for t in result:
        task_id = t.get('id', 0)  # 任务ID
        model = t.get('model', UNIT)  # 计费模式
        rate = t.get('rate', CALL_RATE)  # 呼叫费率
        voice_name = t.get('voice_name', '')  # 语音文件名
        user_id = t.get('user_id', '')  # 用户ID
        re = finish_number(task_id)  # 计算每个呼叫任务
        if not re:return
        for i in re:
            a_time = i.get('a_time', 0)  # 语音时长
            b_time = i.get('b_time', 0)  # 人工时长
            num_qty = i.get('num_qty', 0)  # 总数量
            f_qty = i.get('f_qty', 0)  # 失败数量
            call_fee = int(i.get('call_fee') or 0)  # 结算费用
            s_qty = i.get('s_qty', 0)  # 成功数量
            re_qty = i.get('re_qty', 0)  # 转人工数量
        # 写入群呼任务报表    
        write_task_report(task_id, a_time, b_time, num_qty, s_qty, f_qty, call_fee, re_qty, model, rate, voice_name, user_id, DT, DT)
        # 记录用户消费

# 任务日消费报表
def report_expenses():
    DT = get_dt()
    result = get_user_id(DT)  # 有呼叫任务的用户ID
    if not result:return
    tlist = []
    for u in result:
        uid = u.get('user_id', 0)
        tk = get_task_id(uid)  # 每个用户的呼叫任务ID
        
        for n in tk:
            taskid = str(n.get('id', 0))
            res = taskid.split(",")
            for x in res:
                tlist.append("%s" % x)
        number = ",".join(tlist)
        task_qty = len(tlist)
        exp = get_total(number)  # 任务日消费报表结果
        for r in exp:
            a_time = r.get('a_time', 0)  # 语音时长
            b_time = r.get('b_time', 0)  # 人工时长
            qty = r.get('qty', 0)  # 总数量
            call_fee = r.get('call_fee', 0)  # 结算费用
            re_qty = r.get('redirectret', 0)  # 转人工数量            
            s_qty = r.get('success_num', 0)  # 成功数量
        # 写入任务日消费报表 
        write_expenses_report(a_time, b_time, qty, uid, DT, call_fee, task_qty, re_qty, s_qty)
  
def main():
    sched = Scheduler()
    sched.add_interval_job(scan_task, seconds=5)  # 呼叫
    # sched.add_interval_job(scan_sms, seconds=5)                     # 发送短信
    # sched.add_interval_job(sms_deduction, minutes=1)                # 短信扣费
    # sched.add_interval_job(comebakcallnotify, seconds=3)  # 计费,更新号码状态,任务状态
    thread.start_new_thread(comebakcallnotify, ())
    # thread.start_new_thread(comebakcallnotify, ())    
    # threads.append(threading.Thread(target=comebakcallnotify, args=()))
    # 启动所有线程
    # for t in threads:
    #    t.start()
        
        
    sched.add_interval_job(update_task, seconds=10)  # 更新任务状态
    sched.add_cron_job(report_task, hour=22, minute=0, second=0)  # 群呼任务报表
    sched.add_cron_job(report_expenses, hour=23, minute=0, second=0)  # 任务日消费报表
    sched.start()
    initLog()
    http_server()
        
if __name__ == "__main__":
    main()

